/*
 * File:   vfd.c
 * Author: Marcel
 *
 * Created on 22. Juli 2012, 16:02
 */

#include <p18f2620.h>
#include <usart.h>
#include <stdlib.h>
#include "uart.h"
#include "onewire.h"
#include "vfd.h"

/* Globals */
static unsigned char vfd_buffer[VFD_SIZE];  // Buffer
static unsigned char vfd_cur_pos;       // Current cursor position in buffer

void vfd_init(void) {
    #ifdef UART_OUTPUT
    uart_putrs((const far rom char*) "\n\rInitizalizing VFD");
    #endif
    // Set port directions
    TRISB = 0x00; // Data-Port -> out
    TRISAbits.TRISA3 = 0;
    TRISAbits.TRISA4 = 1;
    TRISAbits.TRISA5 = 0;

    VFD_SEL = 1;	// active-low
    VFD_WR = 1;		// active-low
    VFD_DATA = 0x00;

    
    vfd_putcmd(0x1F);		// Reset VFD
    Nop();
    vfd_putcmd(0x14);		// Cursor Off
    Nop();
    vfd_putcmd(0x11);		// Disable vertical scrolling
    Nop();


    /* Initialize vfd output buffer */
    vfd_clear();

    Nop();
    #ifdef UART_OUTPUT
    uart_putrs((const far rom char*) "\t\t[DONE]");
    #endif
}

/* This function clears the vfd screen */
void vfd_clear(void) {
    int i;
    for(i=0; i<VFD_SIZE; i++) {
        vfd_buffer[i] = ' ';
    }
    vfd_cur_pos = 0;
}

void vfd_pos(unsigned char pos) {
    vfd_cur_pos = pos;
}

void vfd_pos_xy(unsigned char x, unsigned char y) {
    vfd_pos(y*VFD_WIDTH+x);
}

void vfd_putc(unsigned char c) {
    vfd_buffer[vfd_cur_pos] = c;
    if(vfd_cur_pos < VFD_SIZE)
        vfd_cur_pos++;
    else {
        vfd_cur_pos = 0;
    }
}

void vfd_puts(char* string) {
    while(*string) {
        vfd_putc(*string);
        string++;
    }
}

void vfd_putrs(const rom char* string) {
    unsigned char msb = 0x00, lsb = 0x00;
    while(*string) {
        // Check whether a \hxx escape sequence is in string
        if(*string == '\\') {
            if(*++string == 'h') {
                msb = *++string;
                lsb = *++string;
                msb = msb << 4;
                lsb = lsb & 0x0F;
                vfd_putc((unsigned char) msb | lsb);
                string++;
            } else *--string;
        }
        else {
            vfd_putc(*string);
            string++;
        }
    }
}

void vfd_puttemp(unsigned int f, unsigned char pos_x, unsigned char pos_y) {
    unsigned char temp, temp_decimal;

    temp = f / 100;
    temp_decimal = f - temp * 100;

    vfd_pos_xy(pos_x, pos_y);

    vfd_putb(temp);

    vfd_putc((const rom char) ',');
    if(temp_decimal < 10)
        vfd_putc((const rom char) '0');
    vfd_putb(temp_decimal);

    vfd_putrs((const rom char*) "\\h27C");
}

void vfd_puti(int i) {
    char buf[6];   // 5 chars for max. int-value and 1 char for null-termination
    itoa(i, buf);
    vfd_puts(buf);
}

void vfd_putb(unsigned char c) {
    char buf[4];
    btoa(c, buf);
    vfd_puts(buf);
}


void vfd_puthex(unsigned char c) {
    static const rom unsigned char hex[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
    vfd_putc((const rom unsigned char) hex[(c & 0xF0) >> 4]);
    vfd_putc((const rom unsigned char) hex[c & 0x0F]);
}

/* This function redirects commands directly to vfd without buffer */
void vfd_putcmd(unsigned char cmd) {
    INTCONbits.GIEH = 0; // Disable all unmasked interrupts
    INTCONbits.GIEL = 0;    // Disable all peripheral interrupts
    VFD_SEL = 0; Nop();Nop();
    VFD_DATA = cmd; Nop();Nop();
    VFD_WR = 0; Nop();Nop();
    VFD_WR = 1; Nop();Nop();
    VFD_SEL = 1; Nop();Nop();
    while(VFD_BSY) { Nop(); }
    INTCONbits.GIEH = 1; // Enable all unmasked interrupts
    INTCONbits.GIEL = 1;    // Enable all peripheral interrupts
}

void vfd_draw(void) {
    static unsigned char buf = 0;

    if(buf == 0) {
        vfd_putcmd(0x10);           // Set cursor to position 0
        vfd_putcmd(0x00);
    }
    if(VFD_BSY == 0) {
        if(buf >= 40) {
            buf = 0;
        }
        INTCONbits.GIEH = 0; // Disable all unmasked interrupts
        INTCONbits.GIEL = 0;    // Disable all peripheral interrupts
        VFD_SEL = 0; Nop();Nop();
        VFD_DATA = vfd_buffer[buf]; Nop();Nop();
        VFD_WR = 0; Nop();Nop();
        VFD_WR = 1; Nop();Nop();
        VFD_SEL = 1; Nop();Nop();
        INTCONbits.GIEH = 1; // Enable all unmasked interrupts
        INTCONbits.GIEL = 1;    // Enable all peripheral interrupts
        buf++;
    }

}
